package com.nxw.springcloud.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.chanjet.common.endpoint.pojo.ChanjetValueResult;
import com.chanjet.common.endpoint.pojo.ErrorInfo;
import com.nxw.springcloud.gateway.entity.CommonConstants;
import com.nxw.springcloud.gateway.entity.EnvironmentEnum;
import com.nxw.springcloud.gateway.spi.GateWayAdminRemote;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


@Component
public class TokenAuthenticationFilter extends AbstractGatewayFilterFactory {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    @Lazy
    GateWayAdminRemote gateWayAdminRemote;

    @Override
    public GatewayFilter apply(Object config) {

        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            ServerHttpRequest.Builder mutate = request.mutate();
            try {
                String appKey = exchange.getRequest().getHeaders().getFirst(CommonConstants.APP_KEY);
                String appSecret = exchange.getRequest().getHeaders().getFirst(CommonConstants.APP_SECRET);
                String environment = exchange.getRequest().getHeaders().getFirst(CommonConstants.ENVIRONMENT);
                if (!StringUtils.isEmpty(appSecret) && !StringUtils.isEmpty(appKey) && !StringUtils.isEmpty(environment)) {
                    if (redisTemplate.opsForHash().hasKey(environment, appKey)) {
                        return getVoidMono(exchange, chain, request, response, mutate, appKey, appSecret, environment);
                    } else {
                        Mono<Void> bodyDataBuffer = getVoidMono(response, mutate, appKey, appSecret, environment);
                        if (bodyDataBuffer != null) return bodyDataBuffer;
                    }
                } else {
                    DataBuffer bodyDataBuffer = responseErrorInfo(response, HttpStatus.UNAUTHORIZED.value(), "appKey缺失");
                    return response.writeWith(Mono.just(bodyDataBuffer));
                }
            } catch (Exception e) {
                //没有token
                DataBuffer bodyDataBuffer = responseErrorInfo(response, HttpStatus.UNAUTHORIZED.value(), e.getMessage());
                return response.writeWith(Mono.just(bodyDataBuffer));
            }
            ServerHttpRequest build = mutate.build();
            return chain.filter(exchange.mutate().request(build).build());
        };

    }

    private Mono<Void> getVoidMono(ServerHttpResponse response, ServerHttpRequest.Builder mutate, String appKey, String appSecret, String environment) {
        String appKeyAndSecret = gateWayAdminRemote.getAppKey(appKey, EnvironmentEnum.getEnvironmentEnumByValue(environment));
        if (StringUtils.isEmpty(appKeyAndSecret)) {
            DataBuffer bodyDataBuffer = responseErrorInfo(response, HttpStatus.UNAUTHORIZED.value(), "appKey不存在");
            return response.writeWith(Mono.just(bodyDataBuffer));
        } else {
            JSONObject jsonObject = JSONObject.parseObject(appKeyAndSecret);
            if (!appSecret.equals(jsonObject.getString("appSecret"))) {
                DataBuffer bodyDataBuffer = responseErrorInfo(response, HttpStatus.UNAUTHORIZED.value(), "appKey错误");
                return response.writeWith(Mono.just(bodyDataBuffer));
            }
        }
        return null;
    }


    private Mono<Void> getVoidMono(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request, ServerHttpResponse response, ServerHttpRequest.Builder mutate, String appKey, String appSecret, String environment) {
        if (appSecret.equals(redisTemplate.opsForHash().get(environment, appKey))) {
            return chain.filter(exchange.mutate().request(request).build());
        } else {
            DataBuffer bodyDataBuffer = responseErrorInfo(response, HttpStatus.UNAUTHORIZED.value(), "appKey错误");
            return response.writeWith(Mono.just(bodyDataBuffer));
        }
    }

    /**
     * 自定义返回错误信息
     *
     * @param response
     * @param status
     * @param message
     * @return
     */
    public DataBuffer responseErrorInfo(ServerHttpResponse response, int status, String message) {
        HttpHeaders httpHeaders = response.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
        ChanjetValueResult<Object> fail = ChanjetValueResult.fail(ErrorInfo.builder().code(status).msg(message).build());
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.bufferFactory().wrap(JSONObject.toJSONString(fail).getBytes());
    }
}
